package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.*;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-12-18
 */
@Service
@Slf4j
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {


    /**
     * 新增互动提问的问题
     *
     * @param dto
     */
    @Override
    public void addQuestion(QuestionFormDTO dto) {
        //数据转化
        InteractionQuestion interactionQuestion = BeanUtils.copyBean(dto, InteractionQuestion.class);
        //获取当前用户
        Long user = UserContext.getUser();
        interactionQuestion.setUserId(user);
        boolean save = this.save(interactionQuestion);
        if (!save) {
            throw new DbException("新增互动提问的问题失败");
        }
    }

    /**
     * 修改互动提问的问题
     *
     * @param id
     * @param dto
     */
    @Override
    public void updateQuestion(Long id, QuestionFormDTO dto) {
        InteractionQuestion interactionQuestion = BeanUtils.copyBean(dto, InteractionQuestion.class);
        interactionQuestion.setId(id);
        boolean b = this.updateById(interactionQuestion);
        if (!b) {
            throw new DbException("修改互动提问的问题失败");
        }
    }


    @Autowired
    private UserClient userClient;
    @Autowired
    private InteractionReplyMapper replyMapper;

    /**
     * 分页查询互动提问的问题
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery query) {
        Long courseId = query.getCourseId();
        Long sectionId = query.getSectionId();
        if (courseId == null && sectionId == null) {
            throw new BadRequestException("课程id和小节id不能都为空");
        }
        // 2.分页查询
        Page<InteractionQuestion> page = lambdaQuery()
                .select(InteractionQuestion.class, info -> !info.getProperty().equals("description"))
                .eq(query.getOnlyMine(), InteractionQuestion::getUserId, UserContext.getUser())
                .eq(courseId != null, InteractionQuestion::getCourseId, courseId)
                .eq(sectionId != null, InteractionQuestion::getSectionId, sectionId)
                .eq(InteractionQuestion::getHidden, false)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        // 3.根据id查询提问者和最近一次回答的信息
        Set<Long> userIds = new HashSet<>();
        Set<Long> answerIds = new HashSet<>();
        // 3.1.得到问题当中的提问者id和最近一次回答的id
        for (InteractionQuestion q : records) {
            if (!q.getAnonymity()) { // 只查询非匿名的问题
                userIds.add(q.getUserId());
            }
            answerIds.add(q.getLatestAnswerId());
        }

        //3.2清理集合中的null元素
        answerIds.remove(null);
        Map<Long, InteractionReply> replyMap = new HashMap<>();
        //查询id查询最近一次回答
        if (CollUtils.isNotEmpty(answerIds)) {
            List<InteractionReply> replies = replyMapper.selectBatchIds(answerIds);
            for (InteractionReply reply : replies) {
                replyMap.put(reply.getId(), reply);
                //如何不是匿名的，则将用户id放入useIds,用于查询用户信息
                if (!reply.getAnonymity()) {
                    userIds.add(reply.getUserId());
                }
            }
        }
        // 3.3.根据id查询用户信息（提问者）
        userIds.remove(null);
        Map<Long, UserDTO> userMap = new HashMap<>(userIds.size());
        if (CollUtils.isNotEmpty(userIds)) {
            List<UserDTO> users = userClient.queryUserByIds(userIds);
            userMap = users.stream()
                    .collect(Collectors.toMap(UserDTO::getId, u -> u));
        }

        // 4.封装响应数据
        // 4.封装VO
        List<QuestionVO> voList = new ArrayList<>(records.size());

        for (InteractionQuestion record : records) {
            //po->vo
            QuestionVO vo = BeanUtils.copyBean(record, QuestionVO.class);
            vo.setUserId(null);
            //如果问题不是匿名的，则将提问者信息封装到VO中
            if (!record.getAnonymity()) {
                UserDTO userDTO = userMap.get(record.getUserId());
                if (userDTO != null) {
                    vo.setUserId(userDTO.getId());
                    vo.setUserName(userDTO.getName());
                    vo.setUserIcon(userDTO.getIcon());
                }
            }
            InteractionReply reply = replyMap.get(record.getLatestAnswerId());
            if (reply != null) {
                vo.setLatestReplyContent(reply.getContent());
                //如果回答不是匿名的，则将回答者信息封装到VO中
                if (!reply.getAnonymity()) {
                    UserDTO userDTO = userMap.get(reply.getUserId());
                    vo.setLatestReplyUser(userDTO.getName());
                }
            }

            voList.add(vo);
        }

        return PageDTO.of(page, voList);
    }


    /**
     * 根据id查询互动提问的问题
     *
     * @param id
     * @return
     */
    @Override
    public QuestionVO getQuestionById(Long id) {
        if (id == null) {
            throw new BadRequestException("问题id不能为空");
        }

        InteractionQuestion question = getById(id);
        if (question == null || question.getHidden()) {
            return null;
        }
        QuestionVO vo = BeanUtils.copyBean(question, QuestionVO.class);
        if (!question.getAnonymity()) {
            UserDTO userDTO = userClient.queryUserById(question.getUserId());
            if (userDTO != null) {
                vo.setUserName(userDTO.getName());
                vo.setUserIcon(userDTO.getIcon());
            }
        }

        return vo;
    }

    /**
     * 删除互动提问的问题
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteQuestionById(Long id) {
        if (id == null) {
            throw new BadRequestException("问题id不能为空");
        }
        InteractionQuestion question = getById(id);
        if (question == null) {
            throw new BadRequestException("问题不存在");
        }
        if (!question.getUserId().equals(UserContext.getUser())) {
            throw new BadRequestException("只能删除自己创建的问题");
        }
        boolean b = removeById(id);
        if (!b) {
            throw new DbException("删除失败");
        }
        //删除对应的回答
        int delete = replyMapper.delete(Wrappers.<InteractionReply>lambdaQuery()
                .eq(InteractionReply::getQuestionId, id)
        );
        log.info("删除问题{}对应的回答{}条", id, delete);

    }

    @Autowired
    private SearchClient searchClient;
    @Autowired
    private CategoryCache categoryCache;
    @Autowired
    private CourseClient courseClient;
    @Autowired
    private CatalogueClient catalogueClient;


    /**
     * 管理端分页查询互动提问的问题
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<QuestionAdminVO> queryQuestionPageAdmin(QuestionAdminPageQuery query) {

        // 1.处理课程名称，得到课程id
        List<Long> courseIds = null;
        if (StringUtils.isNotBlank(query.getCourseName())) {
            courseIds = searchClient.queryCoursesIdByName(query.getCourseName());
            if (CollUtils.isEmpty(courseIds)) {
                return PageDTO.empty(0L, 0L);
            }
        }

        // 2.分页查询
        Integer status = query.getStatus();
        LocalDateTime begin = query.getBeginTime();
        LocalDateTime end = query.getEndTime();
        Page<InteractionQuestion> page = lambdaQuery()
                .in(courseIds != null, InteractionQuestion::getCourseId, courseIds)
                .eq(status != null, InteractionQuestion::getStatus, status)
                .gt(begin != null, InteractionQuestion::getCreateTime, begin)
                .lt(end != null, InteractionQuestion::getCreateTime, end)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        // 3.准备VO需要的数据：用户数据、课程数据、章节数据
        Set<Long> userIds = new HashSet<>();
        Set<Long> cIds = new HashSet<>();
        Set<Long> cataIds = new HashSet<>();
        // 3.1.获取各种数据的id集合
        for (InteractionQuestion q : records) {
            userIds.add(q.getUserId());
            cIds.add(q.getCourseId());
            cataIds.add(q.getChapterId());
            cataIds.add(q.getSectionId());
        }
        // 3.2.根据id查询用户
        List<UserDTO> users = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userMap = new HashMap<>(users.size());
        if (CollUtils.isNotEmpty(users)) {
            userMap = users.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));
        }

        // 3.3.根据id查询课程
        List<CourseSimpleInfoDTO> cInfos = courseClient.getSimpleInfoList(cIds);
        Map<Long, CourseSimpleInfoDTO> cInfoMap = new HashMap<>(cInfos.size());
        if (CollUtils.isNotEmpty(cInfos)) {
            cInfoMap = cInfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        }

        // 3.4.根据id查询章节
        List<CataSimpleInfoDTO> catas = catalogueClient.batchQueryCatalogue(cataIds);
        Map<Long, String> cataMap = new HashMap<>(catas.size());
        if (CollUtils.isNotEmpty(catas)) {
            cataMap = catas.stream()
                    .collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));
        }


        // 4.封装VO
        List<QuestionAdminVO> voList = new ArrayList<>(records.size());
        for (InteractionQuestion q : records) {
            // 4.1.将PO转VO，属性拷贝
            QuestionAdminVO vo = BeanUtils.copyBean(q, QuestionAdminVO.class);
            voList.add(vo);
            // 4.2.用户信息
            UserDTO user = userMap.get(q.getUserId());
            if (user != null) {
                vo.setUserName(user.getName());
            }
            // 4.3.课程信息以及分类信息
            CourseSimpleInfoDTO cInfo = cInfoMap.get(q.getCourseId());
            if (cInfo != null) {
                vo.setCourseName(cInfo.getName());
                vo.setCategoryName(categoryCache.getCategoryNames(cInfo.getCategoryIds()));
            }
            // 4.4.章节信息
            vo.setChapterName(cataMap.getOrDefault(q.getChapterId(), ""));
            vo.setSectionName(cataMap.getOrDefault(q.getSectionId(), ""));
        }
        return PageDTO.of(page, voList);
    }

    /**
     * 修改问题的隐藏状态
     *
     * @param id
     * @param hidden
     */
    @Override
    public void hiddenQuestionById(Long id, Boolean hidden) {
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BadRequestException("问题不存在");
        }
        if (question.getHidden().equals(hidden)) {
            return;
        }
        question.setHidden(hidden);
        boolean b = updateById(question);
        if (!b) {
            throw new DbException("修改失败");
        }
    }

    /**
     * 管理端根据id查询问题详情
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public QuestionAdminVO getQuestionByIdAdmin(Long id) {
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BadRequestException("问题不存在");
        }
        QuestionAdminVO vo = BeanUtils.copyBean(question, QuestionAdminVO.class);

        //设置提问者信息
        if (question.getUserId() != null) {
            UserDTO userDTO = userClient.queryUserById(question.getUserId());
            vo.setUserName(userDTO.getName());
        }
        //设置课程信息
        if (question.getCourseId() != null) {
            CourseFullInfoDTO courseInfoById = courseClient.getCourseInfoById(question.getCourseId(), false, true);
            vo.setCourseName(courseInfoById.getName());
            List<UserDTO> userDTOS = userClient.queryUserByIds(courseInfoById.getTeacherIds());
            if (CollUtils.isNotEmpty(userDTOS)) {
                vo.setTeacherName(userDTOS.get(0).getName());
            }
            vo.setCategoryName(categoryCache.getCategoryNames(courseInfoById.getCategoryIds()));
        }
        //章节信息
        if (question.getChapterId() != null) {
            ArrayList<Long> list = CollUtils.toList(question.getChapterId(), question.getSectionId());
            List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(list);
            for (CataSimpleInfoDTO cataSimpleInfoDTO : cataSimpleInfoDTOS) {
                if (cataSimpleInfoDTO.getId().equals(question.getChapterId())) {
                    vo.setChapterName(cataSimpleInfoDTO.getName());
                }
            }
        }
        //设置回答数量
        vo.setAnswerTimes(question.getAnswerTimes());
        //修改状态为已查看
        this.lambdaUpdate().eq(InteractionQuestion::getId, id)
                .set(InteractionQuestion::getStatus, QuestionStatus.CHECKED.getValue())
                .update();


        return vo;
    }
}
